#include <os/lock.h>
#include <os/sched.h>
#include <os/list.h>
#include <atomic.h>

mutex_lock_t mlocks[LOCK_NUM];

void init_locks(void)
{
    /* TODO: [p2-task2] initialize mlocks */
}

void spin_lock_init(spin_lock_t *lock)
{
    /* TODO: [p2-task2] initialize spin lock */
    lock->status = UNLOCKED;
}

int spin_lock_try_acquire(spin_lock_t *lock)
{
    /* TODO: [p2-task2] try to acquire spin lock */
    return(lock->status == UNLOCKED);
}

void spin_lock_acquire(spin_lock_t *lock)
{
    /* TODO: [p2-task2] acquire spin lock */
    lock->status = LOCKED;
}

void spin_lock_release(spin_lock_t *lock)
{
    /* TODO: [p2-task2] release spin lock */
    lock->status = UNLOCKED;
}

int do_mutex_lock_init(int key)
{
    /* TODO: [p2-task2] initialize mutex lock */
    int mlock_idx = 0;//key % LOCK_NUM;
    mlocks[mlock_idx].key = key;
    spin_lock_init(&mlocks[mlock_idx].lock);
    list_node_t * self = &mlocks[mlock_idx].block_queue;
    mlocks[mlock_idx].block_queue.prev = self;
    mlocks[mlock_idx].block_queue.next = self;
    return mlock_idx;
}

void do_mutex_lock_acquire(int mlock_idx)
{
    /* TODO: [p2-task2] acquire mutex lock */
    while(1){
    mutex_lock_t *mute_lock = &mlocks[mlock_idx];
    if (spin_lock_try_acquire(&(mute_lock->lock)))
    {
        spin_lock_acquire(&(mute_lock->lock));
        break;
    }
    else
    {
        do_block(&current_running->list, &(mute_lock->block_queue));
       // do_mutex_lock_acquire(mlock_idx);
    }
    }
}

void do_mutex_lock_release(int mlock_idx)
{
    /* TODO: [p2-task2] release mutex lock */
    mutex_lock_t *mute_lock = &mlocks[mlock_idx];
    if (isempyt_queue(&(mute_lock->block_queue)))
    {
        spin_lock_release(&(mute_lock->lock));
    }
    else{
        spin_lock_release(&(mute_lock->lock));
        do_unblock(&(mute_lock->block_queue));
    }
}
